package com.ustc.hewei.rpc.server.net;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.Resource;


/**
* @description: 使用netty来进行网络通信
* @author hewei
* @date 2022/7/27 19:44
* @version 1.0
*/

@Slf4j
public class NettyRpcServer extends RpcServer{

    @Resource
    private ChannelRequestHandler channelRequestHandler;

    private Channel channel;

    public NettyRpcServer(String protocol, int port) {
        super(protocol, port);
    }

    @Override
    public void start() {
        //配置服务器
        //只处理ServerSocketChannel上的accept事件，那么只有一个ServerSocketChannel，是不是需要将线程数设置为1呢
        //其实不用，因为ServerSocketChannel只有一个，在group中创建EventLoop也只会创建一个，即只会绑定一个EventLoop
        //所以其实只会占用一个线程
        EventLoopGroup bossGroup = new NioEventLoopGroup();

        //只处理SocketChannel上的读写
        //理想的情况下，一个线程对应一个eventLoop，对应一个客户端，对应一个channel，当设置的线程不够用时，会多路复用
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ChannelFuture channelFuture = new ServerBootstrap().group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 500)
                    //设置控制台中日志的级别
                    .handler(new LoggingHandler(LogLevel.INFO))
                    //设置子信息处理器，调用自定义的处理器
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(channelRequestHandler);
                        }
                    }).bind(port).sync();
            log.info("服务端网络启动成功！");
            channel = channelFuture.channel();
            //使线程阻塞在这里，监听对应端口，直到接收到关闭通道的信号，停止阻塞
            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("服务端网络启动失败!", e);
            e.printStackTrace();
            stop();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    @Override
    public void stop() {
        System.out.println("stop方法");
        channel.close();
    }
}
